package com.bdbit.ChargingStation.services;

import com.bdbit.ChargingStation.config.MqttProperties;
import com.bdbit.ChargingStation.entity.ChargingPile;
import com.bdbit.ChargingStation.mapper.ChargingPileMapper;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

@Service
@Slf4j
public class MqttServerService implements MqttCallbackExtended {
    @Autowired
    MqttMessageListener mqttMessageListener;
    @Autowired
    private ChargingPileMapper chargingPileMapper;
    private final MqttProperties mqttProperties;
    private MqttClient mqttClient;
    // 服务端消息标记
    private static final String SERVER_TAG = "[SERVER]";
    private final MqttMessageService messageService;

    // 消息计数器
    private final AtomicInteger messageSentCounter = new AtomicInteger(0);
    private final AtomicInteger messageReceivedCounter = new AtomicInteger(0);

    @Autowired
    public MqttServerService(MqttProperties mqttProperties,
                             @Qualifier("chargingMessageServiceImpl") @Lazy MqttMessageService messageService) {
        this.mqttProperties = mqttProperties;
        this.messageService = messageService;
    }

    public String getDeviceSubscribeTopic() {
        return mqttProperties.getDeviceSubscribeTopic();
    }

    @PostConstruct
    public void init() {
        try {
            String clientId = "server_" + UUID.randomUUID().toString().substring(0, 8);

            mqttClient = new MqttClient(
                    mqttProperties.getBrokerUrl(),
                    clientId,
                    new MemoryPersistence()
            );

            MqttConnectOptions options = new MqttConnectOptions();
            options.setCleanSession(true);
            options.setUserName(mqttProperties.getUsername());
            options.setPassword(mqttProperties.getPassword().toCharArray());
            options.setConnectionTimeout(30);
            options.setKeepAliveInterval(300);
            options.setAutomaticReconnect(true);

            mqttClient.setCallback(this);

            mqttClient.connect(options);
            log.info("MQTT连接建立成功 | Broker: {}", mqttProperties.getBrokerUrl());

            subscribeToTopics();

        } catch (MqttException e) {
            log.error("MQTT服务初始化失败: {}", e.getMessage());
        }
    }

    private void subscribeToTopics() {
        try {
            //String devicePublishTopic = mqttProperties.getDevicePublishTopic();
            //mqttClient.subscribe(devicePublishTopic, 2);

            //查询全部id
            List<ChargingPile> resultList = chargingPileMapper.selectAll();
            for(int i=0;i<resultList.size();i++) {
                String devicePublishTopic = resultList.get(i).getIccid();
                mqttClient.subscribe(devicePublishTopic, 2);
                log.info("已订阅设备消息主题: {}", devicePublishTopic);
            }
        } catch (MqttException e) {
            log.error("订阅主题失败: {}", e.getMessage());
        }
    }

    public void sendToDevice(String deviceId, String message) {
        if (deviceId == null || deviceId.isEmpty()) {
            log.warn("无法发送消息，设备ID为空");
            return;
        }

        try {
            if (isConnected()) {
                sendToDeviceInternal(deviceId, message);
            } else {
                // 关键修复：连接断开时缓存消息
                log.warn("连接断开，缓存待发送消息 | 主题: {}, 内容: {}", deviceId, message);
                pendingMessages.put(deviceId, message);
            }
        } catch (Exception e) {
            log.error("向设备发送消息失败: {}", e.getMessage());
        }
    }
    private final Map<String, String> pendingMessages = new ConcurrentHashMap<>();

    public boolean isConnected() {
        return mqttClient != null && mqttClient.isConnected();
    }

    /**
     * 实际发送消息
     */
    private void sendToDeviceInternal(String deviceId, String message) throws MqttException {
        // 关键修复：付款指令不加SERVER_TAG
        String fullMessage = message;

        // 只有指令类消息加标记
        if (!isPaymentCommand(message)) {
            fullMessage = SERVER_TAG + message;
        }

        MqttMessage mqttMessage = new MqttMessage(fullMessage.getBytes());
        //mqttMessage.setRetained(false); // 设置保留标志为true
        mqttMessage.setQos(2);
        mqttClient.publish(deviceId, mqttMessage);

        // 优化日志：只记录前10条消息，之后每100条记录一次
        int count = messageSentCounter.incrementAndGet();
        if (count <= 10 || count % 100 == 0) {
            log.info("已发送 {} 条消息至设备 | 最后主题: {}", count, deviceId);
        } else if (log.isDebugEnabled()) {
            log.debug("消息已发送至设备 | 主题: {}, 内容: {}", deviceId, fullMessage);
        }
    }

    /**
     * 判断是否是付款指令（关键修复）
     */
    private boolean isPaymentCommand(String message) {
        if (message == null || message.isEmpty()) {
            return false;
        }

        // 清理消息内容
        String cleanMessage = message.trim();

        // 付款指令格式: IMEI.金额.模式
        // 修复1: 允许金额少于3位（如1元=001）
        // 修复2: 允许模式为1位或2位
        Pattern pattern = Pattern.compile("^\\d+\\.\\d{1,3}\\.\\d{1,2}$");
        return pattern.matcher(cleanMessage).matches();
    }

    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        if (reconnect) {
            log.info("MQTT重新连接成功");
            subscribeToTopics();

            // 关键修复：重连后重新发送待处理消息
            resendPendingMessages();
        } else {
            log.info("MQTT首次连接成功");
        }
    }

    /**
     * 重连后重新发送待处理消息
     */
    private void resendPendingMessages() {
        if (pendingMessages.isEmpty()) return;

        log.info("重新发送{}条待处理消息", pendingMessages.size());
        pendingMessages.forEach((topic, message) -> {
            try {
                sendToDeviceInternal(topic, message);
                if (log.isDebugEnabled()) {
                    log.debug("消息已重新发送 | 主题: {}, 内容: {}", topic, message);
                }
            } catch (Exception e) {
                log.error("消息重发失败", e);
            }
        });
        pendingMessages.clear();
    }

    @Override
    public void connectionLost(Throwable cause) {
        log.warn("MQTT连接丢失: {}", cause.getMessage());
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) {
        String payload = new String(message.getPayload());

        // 优化日志：只记录前10条消息，之后每100条记录一次
        int count = messageReceivedCounter.incrementAndGet();
        if (count <= 10 || count % 100 == 0) {
            log.info("收到 {} 条设备消息 | 最后主题: {}", count, topic);
        } else if (log.isDebugEnabled()) {
            log.debug("收到设备消息 | 主题: {}, 内容: {}", topic, payload);
        }

        // 将消息交给统一的消息处理服务
        String response = messageService.processMessage(topic, payload);
        if (response != null && !response.isEmpty()) {
            sendToDevice(topic, response);
            if (log.isDebugEnabled()) {
                log.debug("已回复设备 | 主题: {}, 内容: {}", topic, response);
            }
        }
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        if (log.isDebugEnabled()) {
            log.debug("消息传递完成");
        }
    }
}